#include "Piece.hpp"
#include "CriticalException.hpp"
#include "Cell.hpp"
#include "Chessboard.hpp"

#define C_CONTAINS_PIECE(POS, COLOR)																\
	((Chess::getInstance()->getChessboard()->getCell(POS)->hasPiece()) 								\
	 && (Chess::getInstance()->getChessboard()->getCell(POS)->getPiece()->getColor() == COLOR))


#define CELL_CONTAINS_PIECE_POS_CCOLOR()								\
	C_CONTAINS_PIECE((Position(xtmp, ytmp, p.getColor())), (p.color))


#define CELL_CONTAINS_PIECE_POS_OCOLOR()													\
	C_CONTAINS_PIECE(Position(xtmp, ytmp, p.getColor()), Chess::oppositeColor(p.color))


#define ADD_VALABLE()													\
	if (!Position::isGood(xtmp, ytmp))									\
		break;															\
	if (CELL_CONTAINS_PIECE_POS_CCOLOR())								\
		break;															\
	valables.push_back(new Position(xtmp, ytmp, p.getColor()));			\
	if (CELL_CONTAINS_PIECE_POS_OCOLOR())								\
		break;


#define INIT_VARS()														\
		int x, y, i, xtmp, ytmp;										\
		Position pos = p.getCell()->getPosition();						\
		pos.setColor(p.getColor());										\
		x = pos.getX();													\
		y = pos.getY();


#define LOOP_INCR_PARAMS(XTMP, YTMP)			\
		xtmp = (XTMP);							\
		ytmp = (YTMP);


#define METHOD_CODE(XTMP, YTMP)					\
		INIT_VARS();							\
		for (i = 1 ; i < 8 ; i++)				\
		{										\
			LOOP_INCR_PARAMS(XTMP, YTMP);		\
			ADD_VALABLE();						\
		}

void Piece::left_horizontal(const Piece& p, list<Position*>& valables)
{	METHOD_CODE(x - i, y);		}

void Piece::right_horizontal(const Piece& p, list<Position*>& valables)
{	METHOD_CODE(x + i, y);		}

void Piece::up_vertical(const Piece& p, list<Position*>& valables)
{	METHOD_CODE(x, y + i);		}

void Piece::down_vertical(const Piece& p, list<Position*>& valables)
{	METHOD_CODE(x, y - i);		}
	
void Piece::up_left_diagonal(const Piece& p, list<Position*>& valables)
{	METHOD_CODE(x - i, y + i);	}

void Piece::up_right_diagonal(const Piece& p, list<Position*>& valables)
{	METHOD_CODE(x + i, y + i);	}

void Piece::down_left_diagonal(const Piece& p, list<Position*>& valables)
{	METHOD_CODE(x - i, y - i);	}


void Piece::down_right_diagonal(const Piece& p, list<Position*>& valables)
{	METHOD_CODE(x + i, y - i);	}


Piece::Piece(Chess::Color color, Piece::Type type, const Position& pos)
	: color(color), type(type), cell(0), nb_movements(0)
{
	if (Chess::getInstance()->getChessboard()->getCell(pos)->hasPiece())
		throw new CriticalException("Piece::Piece the cell has already a piece on it !");
		
	Chess::getInstance()->getChessboard()->getCell(pos)->setPiece(this);
	this->cell = Chess::getInstance()->getChessboard()->getCell(pos);
}

Piece::~Piece()
{}


Chess::Color Piece::getColor() const
{	return this->color;	}

Piece::Type	 Piece::getType() const
{	return this->type;	}

void	Piece::setCell(Cell* c)
{	this->cell = c;	}

void	Piece::setOut()
{	this->cell = 0;	}

bool	Piece::isOut() const
{	return (this->cell == 0);	}

Cell*	Piece::getCell() const
{	return this->cell;	}

void	Piece::incrNbMovements()
{	nb_movements++;	}

unsigned int	Piece::getNbMovements() const
{	return nb_movements;	}

void	Piece::setNbMovements(unsigned int val)
{	nb_movements = val;	}
